package guilib;

/***
 * @author Sebastian Mæland Pedersen
 * @author Ragnvald Fuglestein
 */

import java.util.ArrayList;

import javax.swing.SwingUtilities;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import library.Library;

import baseStructure.Album;
import baseStructure.Artist;
import baseStructure.BaseListListener;
import baseStructure.Log;
import baseStructure.Track;

public class LibraryTreeModel implements TreeModel, BaseListListener {	

	public LibraryTreeModel() {
		Library.getInstance().artists.addChangeListener(this);
		Library.getInstance().artists.addInsertListener(this);
		Library.getInstance().artists.addRemoveListener(this);
		Library.getInstance().artists.addStructureListener(this);
	}

	@Override public Object getChild(Object parent, int index) {
		if (index < 0) return null;
		if (parent instanceof LibraryTreeModel) { return Library.getInstance().artists.get(index); }
		if (parent instanceof Artist) {
			int sizeAlbum = ((Artist) parent).getAlbums().size();
			
			if (index < sizeAlbum) return ((Artist) parent).getAlbums().get(index);
			else return ((Artist) parent).getTracks().get(index-sizeAlbum);
		}
		if (parent instanceof Album) {
			return ((Album) parent).getTracks().get(index);
		}
		
		return null;
	}

	@Override public int getChildCount(Object parent) {
		if (parent instanceof LibraryTreeModel) { return Library.getInstance().artists.size(); }
		if (parent instanceof Artist) { return ((Artist) parent).getAlbums().size() + ((Artist) parent).getTracks().size(); }
		if (parent instanceof Album) { return ((Album) parent).getTracks().size(); }
		
		return 0;
	}
	
	@Override public int getIndexOfChild(Object parent, Object child) {
		if (parent instanceof Artist) {
			if (child instanceof Album) {
				return ((Artist) parent).getAlbums().indexOf((Album) child);
			}
			else if (child instanceof Track) {
				return ((Artist) parent).getTracks().indexOf((Track) child);
			}
		}
		
		else if (parent instanceof Album && child instanceof Track) {
			return ((Album) parent).getTracks().indexOf((Track) child);
		}
		
		return -1;
	}

	@Override public Object getRoot() {
		return this;
	}

	@Override public boolean isLeaf(Object node) {
		return getChildCount(node) == 0;
	}

	final ArrayList<TreeModelListener> listeners = new ArrayList<>(3);

	@Override public void addTreeModelListener(TreeModelListener l) {
		listeners.add(l);
	}


	@Override public void removeTreeModelListener(TreeModelListener l) {
		listeners.remove(l);
	}


	@Override public void valueForPathChanged(TreePath arg0, Object arg1) {
		
	}
	
	public void fireStructureChanged(final TreeModelEvent e) {
		for (final TreeModelListener l : listeners) {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					l.treeStructureChanged(e);
				}
			});
		}
	}
	
	public void fireNodeRemoved(final TreeModelEvent e) {
		for (final TreeModelListener l : listeners) {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					l.treeNodesRemoved(e);
				}
			});
		}
	}
	
	public void fireNodeInserted(final TreeModelEvent e) {
		for (final TreeModelListener l : listeners) {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					l.treeNodesInserted(e);
				}
			});
		}
	}
	
	public void fireNodeChanged(final TreeModelEvent e) {
		for (final TreeModelListener l : listeners) {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					l.treeNodesChanged(e);
				}
			});
		}
	}

	private static TreeModelEvent buildPath(LibraryTreeModel model, final Object o, int index) {
		Object[] path = new Object[1];
		path[0] = model;
		int[] childIndices = new int[1];
		childIndices[0] = index;
		Object[] children = new Object[1];
		children[0] = o;
		return new TreeModelEvent(model, path, childIndices, children);
		
	}

	@Override public void baseListChanged(final Object o) {
		TreeModelEvent e = buildPath(this, o, Library.getInstance().artists.indexOf((Artist) o));
		fireNodeChanged(e);
	}

	@Override public void baseListInserted(final Object o) {
		if(o == null) Log.d("LibraryTreeModel.baseListInserted");
		int index = Library.getInstance().artists.indexOf((Artist) o);
		TreeModelEvent e = buildPath(this, o, index);
		
		if (index != 0)
			fireNodeInserted(e);
		
		else { fireStructureChanged(e); }
	}

	@Override public void baseListRemoved(final Object o) {
		TreeModelEvent e = buildPath(this, o, Library.getInstance().artists.indexOf((Artist) o));
		fireNodeRemoved(e);
	}

	@Override public void baseListStructureChanged() { //TODO FIX THIS WRECK
		//fireStructureChanged();
	}
}
